import * as $apis from '@/api/'
import { DefaultShareConfig } from '@/api/config.js'
import $mRoutesIdx from '@/common/router/routes.idx'
import store from '@/store'
// #ifdef APP-PLUS
import permission from '@/common/permission'
// #endif

interface RouterParams {
	path: string
	query?: { [key: string]: any }
}

const router = {
	/**
	 * @name 动态跳转
	 * @param data.app_page.route 动态跳转的路由
	 * @param data.params 动态跳转的参数
	 */
	navigateToIdx(data: { app_page: object; params: object }) {
		if (data.app_page) {
			$mRoutesIdx.navigateToIdx(data.app_page, data.params)
		}
	},
	/**
	 * @name str转params对象参数
	 * @param params 传入字符串参数
	 * @example a=1&b=2 => {a:1, b:2}
	 */
	strParseParam(params: string) {
		let theQuery: { [key: string]: any } = {}
		let strs = params.split('&')
		for (let i = 0; i < strs.length; i++) {
			theQuery[strs[i].split('=')[0]] = strs[i].split('=')[1]
		}
		return theQuery
	},
	/**
	 * @name obj转params字符串参数
	 * @param obj 传入对象参数
	 * @example {a:1, b:2} => a=1&b=2
	 */
	objParseParam(obj: RouterParams['query']) {
		let paramsStr = ''
		if (obj instanceof Array) return paramsStr
		if (!(obj instanceof Object)) return paramsStr
		for (let key in obj) {
			paramsStr += `${key}=${obj[key]}&`
		}
		return paramsStr.substring(0, paramsStr.length - 1)
	},
	/**
	 * @name obj转路由地址带参数
	 * @param route 传入路由和参数对象
	 * @example {path: 'pages/index/index', query: {a: 1, b: 2}} => /pages/index/index?a=1&b=2
	 */
	objParseUrlAndParam(route: RouterParams) {
		let paramsStr = ''
		let url = route.path || '/'
		if (route.query instanceof Array) return url
		if (!(route.query instanceof Object)) return url
		paramsStr = this.objParseParam(route.query)
		if (paramsStr) url += '?'
		url += paramsStr
		return url
	},
	/**
	 * @name 校验路由过滤参数
	 * @param route 传入路由和参数对象 或 路由字符串
	 * @example {path: 'pages/index/index', query: {}} || /pages/index/index
	 */
	filterParams(route: RouterParams | string) {
		// 传入纯路由字符串初始化对象
		if (typeof route == 'string') {
			route = {
				path: route,
				query: {}
			}
		}
		// 容错处理，未传斜杠自动补全
		if (route.path[0] !== '/') {
			route.path = `/${route.path}`
		}
		// 循环过滤参数，防止报错
		for (let i in route.query) {
			if (route.query[i] === null || route.query[i] == undefined) {
				delete route.query[i]
			}
		}
		return route
	},
	/**
	 * @name 保留当前页面，跳转到应用内的某个页面
	 * @param route 传入路由和参数对象 或 路由字符串
	 * @example {path: 'pages/index/index', query: {}} || /pages/index/index
	 */
	push(route: RouterParams | string) {
		uni.navigateTo({
			url: this.objParseUrlAndParam(this.filterParams(route))
		})
	},
	/**
	 * @name 跳转到tabBar页面，并关闭其他所有非tabBar页面
	 * @param route 传入路由和参数对象 或 路由字符串
	 * @example {path: 'pages/index/index', query: {}} || /pages/index/index
	 */
	pushTab(route: RouterParams | string) {
		uni.switchTab({
			url: this.objParseUrlAndParam(this.filterParams(route))
		})
	},
	/**
	 * @name 关闭当前页面，跳转到应用内的某个页面
	 * @param route 传入路由和参数对象 或 路由字符串
	 * @example {path: 'pages/index/index', query: {}} || /pages/index/index
	 */
	replace(route: RouterParams | string) {
		uni.redirectTo({
			url: this.objParseUrlAndParam(this.filterParams(route))
		})
	},
	/**
	 * @name 关闭所有页面，打开到应用内的某个页面
	 * @param route 传入路由和参数对象 或 路由字符串
	 * @example {path: 'pages/index/index', query: {}} || /pages/index/index
	 */
	replaceAll(route: RouterParams | string) {
		uni.reLaunch({
			url: this.objParseUrlAndParam(this.filterParams(route))
		})
	},
	/**
	 * @name 关闭当前页面，返回上一页面或多级页面
	 * @param delta 返回的页面数
	 */
	back(delta = 1) {
		uni.navigateBack({
			delta
		})
	},
	/**
	 * @name 跳转小程序
	 * @param path 页面路径
	 * @param query 页面onload(options)需要的参数 （地址栏传参)
	 * @param extraData 跳转目标小程序需要的参数
	 * @param env 跳转目标小程序的版本（有效值： develop（开发版），trial（体验版），release（正式版)
	 * @param appId 跳转目标小程序的APPID，需要先在配置文件注册APPID (默认跳直播小程序)
	 */
	// #ifdef MP-WEIXIN
	navigateToMiniProgram(option: any = {}) {
		const { id } = store.user.userData.userInfo
		const options = {
			path: 'pages/index/index',
			query: {},
			extraData: {},
			env: 'trial',
			appId: 'wx1404dfa1429fac30',
			...option
		}
		const query = {
			invite_id: id,
			fromPlatform: 'shop',
			...options.query
		}
		uni.navigateToMiniProgram({
			path: this.objParseUrlAndParam({ path: options.path, query }),
			appId: options.appId,
			extraData: options.extraData,
			envVersion: options.env,
			success(res) {
				if (option.success) option.success(res)
			},
			fail(err) {
				if (option.fail) option.fail(err)
			},
			complete() {
				if (option.complete) option.complete()
			}
		})
	},
	/**
	 * @name 跳转回上一个小程序，只有当另一个小程序跳转到当前小程序时才会能调用成功
	 * @param extraData 跳转目标小程序需要的参数
	 */
	navigateBackMiniProgram(extraData = {}) {
		uni.navigateBackMiniProgram({
			extraData
		})
	}
	// #endif
}

const utils = {
	/**
	 * @name 字符串参数中取某个参数值
	 * @param name 传入获取的参数字段
	 * @param query 传入获取的字符串参数
	 * @example let str = a=1&b=2 => getQueryString('a', str)
	 */
	getQueryString(name: string, query: string) {
		let reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i')
		let r = query.match(reg)
		if (r !== null) {
			return unescape(r[2])
		}
		return null
	},
	/**
	 * @name 计算过去的时间
	 * @param  {[Date]} time
	 * @return ['01', '00', '00']
	 */
	countTime(time: any) {
		// 格式化时间
		function num(n: any) {
			return n < 10 ? `0${n}` : n
		}
		// 当前时间戳
		let timestamp = new Date().getTime()
		// 过去时间戳
		let endtimes = new Date(time && time.replace(/-/g, '/')).getTime()
		// 过去时间戳大于当前时间戳则return
		if (endtimes > timestamp) {
			return 0
		}
		// 算出中间差，以毫秒数返回
		let countDown = timestamp - endtimes
		// 获取小时数
		let oHour = parseInt(`${countDown / 1000 / 60 / 60}`)
		// 获取分钟数
		let oMinute = parseInt(`${(countDown / 1000 / 60) % 60}`)
		// 获取秒数
		let oSecond = parseInt(`${(countDown / 1000) % 60}`)
		// 输出时间
		return [num(oHour), num(oMinute), num(oSecond)]
	},
	/**
	 * @name 计算未来的时间
	 * @param  {[Date]} time
	 * @return ['01', '00', '00']
	 */
	countDown(time: any, startTime = new Date()) {
		// 格式化时间
		function num(n: any) {
			return n < 10 ? `0${n}` : n
		}
		// 结束时间
		let endTime = new Date(time)
		// 算出中间差，以毫秒数返回
		let countDown = endTime.getTime() - startTime.getTime()
		// 获取天数
		let oDay = parseInt(`${countDown / 1000 / 60 / 60 / 24}`)
		// 获取小时数
		let oHour = parseInt(`${(countDown / 1000 / 60 / 60) % 24}`)
		// 获取分钟数
		let oMinute = parseInt(`${(countDown / 1000 / 60) % 60}`)
		// 获取秒数
		let oSecond = parseInt(`${(countDown / 1000) % 60}`)
		// 输出时间
		if (oDay <= 0 && oHour <= 0 && oMinute <= 0 && oSecond <= 0) {
			return 0
		}
		return [num(oDay), num(oHour), num(oMinute), num(oSecond)]
	},
	/**
	 * @name 处理页面option值接收不到的情况
	 * @param  options 页面的onLoad options
	 */
	filterOption(options?: any) {
		return new Promise(resolve => {
			let res: { [key: string]: any } = {}
			let count = 0
			let timer: any = null
			let newOption: any = null
			console.log('filterOption utils 1', options)
			if (options && Object.keys(options).length) {
				// 扫码，跳登录后再回跳，存在scene
				if (options.scene) {
					res = uni.getStorageInfoSync() // 同步获取当前 storage 的相关信息。
					if (res.keys.includes('codeScene')) {
						newOption = uni.getStorageSync('codeScene')
						console.log('filterOption utils 6', newOption)
						resolve(newOption)
					} else {
						timer = setInterval(() => {
							let thisStorage = uni.getStorageInfoSync() // 同步获取当前 storage 的相关信息。
							if (count == 10) {
								clearInterval(timer)
								console.log('filterOption utils 10次未获取到参数', newOption)
							}
							if (thisStorage.keys.includes('codeScene')) {
								clearInterval(timer)
								newOption = uni.getStorageSync('codeScene')
								console.log('filterOption utils 4', newOption)
								resolve(newOption)
							}
							count++
						}, 200)
					}
				} else {
					console.log('filterOption utils 3', options)
					resolve(options)
				}
			} else {
				res = uni.getStorageInfoSync() // 同步获取当前 storage 的相关信息。
				if (res.keys.includes('codeScene')) {
					newOption = uni.getStorageSync('codeScene')
					console.log('filterOption utils 7', newOption)
					resolve(newOption)
				} else {
					timer = setInterval(() => {
						let thisStorage = uni.getStorageInfoSync() // 同步获取当前 storage 的相关信息。
						if (count == 10) {
							clearInterval(timer)
							console.log('filterOption utils 10次未获取到参数', newOption)
						}
						if (thisStorage.keys.includes('codeScene')) {
							clearInterval(timer)
							newOption = uni.getStorageSync('codeScene')
							console.log('filterOption utils 4', newOption)
							resolve(newOption)
						}
						count++
					}, 200)
				}
			}
		})
	},
	/**
	 * @name showToast 显示消息提示框
	 * @param title 提示的内容，长度与 icon 取值有关。
	 * @param icon 图标，有效值详见上方说明，默认：success。
	 * @param duration 提示的延迟时间，单位毫秒，默认：1500
	 * @param callback 接口调用结束的回调函数（调用成功、失败都会执行）
	 */
	tip(
		title: string,
		icon: 'success' | 'loading' | 'error' | 'none' = 'none',
		duration = 1500,
		callback: any = null
	) {
		uni.showToast({
			title,
			icon,
			duration,
			complete: () => {
				if (callback) {
					const timer = setTimeout(() => {
						clearTimeout(timer)
						return callback()
					}, duration)
				}
			}
		})
	},
	/**
	 * @name 当前设备是否是IOS系统
	 */
	isIOSPlatform() {
		return uni.getSystemInfoSync().platform == 'ios'
	},
	// #ifdef H5
	/**
	 * @name 当前是否是Android下的微信浏览器
	 */
	isAndroidWebview() {
		let ua = navigator.userAgent
		return ua.includes('Android')
	},
	/**
	 * @name 当前是否是IOS下的微信浏览器
	 */
	isIOSWebview() {
		return !this.isAndroidWebview()
	},
	// #endif
	/**
	 * @name 富文本转译
	 * @param {*} str 要转译文本
	 * @return 转译后结果
	 */
	transTag(str: string) {
		if (str) {
			return str
				.replace(/^width:.*?px;/g, '')
				.replace(/^height:.*?px;/g, '')
				.replace(/^width=".*?"/g, '')
				.replace(/^height=".*?"/g, '')
				.replace(/<img/g, '<img style="display:block;max-width:100%;"')
				.replace(/<span style="/g, '<span style="line-height: 1.1em;')
		}
	},
	/**
	 * @name 计算区域高度
	 * @param {*} h 要减去的高度（动态计算DOM）
	 * @return 计算后的区域高度
	 */
	getHeight(h = 0, customBar = uni.getStorageSync('customBar')) {
		let screenHeight = ''
		let windowHeightTemp = 0
		let statusBar = uni.getStorageSync('statusBar')
		let windowHeight = uni.getSystemInfoSync().screenHeight
		let safeArea = uni.getSystemInfoSync().safeAreaInsets?.bottom || 0

		// TABBAR页面处理获取可视区高度有误问题
		if (getCurrentPages()[0].route?.includes('pages/index')) {
			if (windowHeightTemp && windowHeight != windowHeightTemp) {
				windowHeight = windowHeightTemp
			}
			windowHeightTemp = windowHeight
		}

		// #ifdef H5
		let ua = window.navigator.userAgent.toLowerCase()
		if ((ua.match(/MicroMessenger/i) as any) == 'micromessenger') {
			screenHeight = `${windowHeight - customBar - statusBar - h}px`
		} else {
			screenHeight = `${windowHeight - customBar - statusBar - safeArea - h}px`
		}
		// #endif

		// #ifndef H5
		screenHeight = `${windowHeight - customBar - safeArea - h}px`
		// #endif

		return screenHeight
	},
	/**
	 * @name 支付（APP微信支付、APP支付宝支付、微信小程序支付）
	 * @param data 支付参数
	 * @param callback 回调函数
	 */
	requestPayment(data: any, callback: any) {
		let payData: { [key: string]: any } = {
			success: (res: any) => {
				if (callback) {
					return callback({
						success: true,
						data: res
					})
				}
			},
			fail: (err: any) => {
				if (callback) {
					return callback({
						success: false,
						data: err
					})
				}
			}
		}

		if (data.type == 'mp-weixin') {
			// 微信小程序
			payData.provider = 'wxpay'
			payData.timeStamp = data.timeStamp
			payData.nonceStr = data.nonceStr
			payData.package = data.package
			payData.signType = data.signType
			payData.paySign = data.paySign
		} else if (data.type == 'mp-alipay') {
			// 支付宝小程序
			payData.provider = 'alipay'
			payData.orderInfo = 'orderInfo'
			payData.tradeNO = data.trade_no
		} else if (data.type == 'wxpay') {
			// app 微信
			payData.provider = 'wxpay'
			payData.orderInfo = data.url
		} else if (data.type == 'alipay') {
			// app 支付宝
			payData.provider = 'alipay'
			payData.orderInfo = data.url
		} else if (data.type == 'baidu') {
			// 百度小程序
			payData.provider = 'baidu'
			payData.orderInfo = data.url
		}
		uni.requestPayment(payData as UniApp.RequestPaymentOptions)
	},
	/**
	 * @name 小程序订阅消息
	 * @param tmplIds 订阅的消息模板的id的集合
	 */
	requestSubscribeMessage(options: any) {
		uni.requestSubscribeMessage({
			tmplIds: options.tmplIds,
			success: res => {
				if (options.success) options.success(res)
			},
			fail: err => {
				if (err.errCode == 10001) {
					this.tip('参数传空了')
				} else if (err.errCode == 10002) {
					this.tip('网络问题，请求消息列表失败')
				} else if (err.errCode == 10003) {
					this.tip('网络问题，订阅请求发送失败')
				} else if (err.errCode == 10004) {
					this.tip('参数类型错误')
				} else if (err.errCode == 10005) {
					this.tip('无法展示 UI，一般是小程序这个时候退后台了导致的')
				} else if (err.errCode == 20001) {
					this.tip('没有模板数据，一般是模板 ID 不存在 或者和模板类型不对应 导致的')
				} else if (err.errCode == 20002) {
					this.tip('模板消息类型 既有一次性的又有永久的')
				} else if (err.errCode == 20003) {
					this.tip('模板消息数量超过上限')
				} else if (err.errCode == 20004) {
					this.tip('用户关闭了主开关，无法进行订阅')
				} else if (err.errCode == 20005) {
					this.tip('小程序被禁封')
				}
				if (options.fail) options.fail(err)
			},
			complete: res => {
				if (options.complete) options.complete(res)
			}
		})
	},
	/**
	 * @name 获取用户定位
	 * @param reason 是否引导开启定位
	 */
	getLocation(reason = true): Promise<UniNamespace.GetLocationSuccess> {
		return new Promise(resolve => {
			uni.getLocation({
				type: 'gcj02',
				success: res => {
					resolve(res)
				},
				fail: err => {
					if (!reason) {
						return resolve(err)
					}
					// 隐藏Loading
					uni.hideLoading()

					// #ifdef MP-WEIXIN
					// 微信没获取位置权限
					if (err.errMsg == 'getLocation:fail auth deny') {
						uni.authorize({
							scope: 'scope.userLocation',
							fail: () => {
								uni.showModal({
									content: '需要授权位置信息',
									confirmText: '确认授权',
									success: res => {
										if (res.confirm) {
											uni.openSetting({
												success: res => {
													if (res.authSetting['scope.userLocation']) {
														// 授权成功
														this.tip('授权成功')
													} else {
														// 未授权
														this.tip('授权失败')
													}
												}
											})
										} else if (res.cancel) {
											// 取消授权
											this.tip('需要开启位置信息')
										}
									}
								})
							}
						})
					}
					if (err.errMsg == 'getLocation:fail system permission denied') {
						this.tip('需开启定位服务，请确认微信开启了定位权限')
					}
					if (err.errCode == 2) {
						this.tip('请开启定位开关')
					}
					// #endif

					// #ifdef APP-PLUS
					uni.getSystemInfo({
						success: async res => {
							if (res.platform == 'ios') {
								// IOS
								let cllocationManger: any = (plus.ios as any).import('CLLocationManager')
								let enable: any = cllocationManger.locationServicesEnabled()
								let status: any = cllocationManger.authorizationStatus()
								plus.ios.deleteObject(cllocationManger)

								if (enable && status == 2) {
									uni.showModal({
										title: '温馨提示',
										content: '请打开定位服务功能',
										success: res => {
											if (res.confirm) {
												plus.runtime.openURL('app-settings://')
											} else {
												this.tip('需要开启位置信息才能继续操作')
											}
										}
									})
								} else {
									uni.showModal({
										title: '温馨提示',
										content: '请前往设置-隐私-定位服务打开定位服务功能',
										showCancel: false, // 不显示取消按钮
										success() {
											let UIApplication: any = (plus.ios as any).import('UIApplication')
											let application2: any = UIApplication.sharedApplication()
											let NSURL2: any = (plus.ios as any).import('NSURL')
											let setting2: any = NSURL2.URLWithString(
												'App-Prefs:root=Privacy&path=LOCATION'
											)
											application2.openURL(setting2)
											plus.ios.deleteObject(setting2)
											plus.ios.deleteObject(NSURL2)
											plus.ios.deleteObject(application2)
										}
									})
								}
							} else if (res.platform == 'android') {
								// 安卓
								let context: any = plus.android.importClass('android.content.Context')
								let locationManager: any = plus.android.importClass(
									'android.location.LocationManager'
								)
								let main: any = plus.android.runtimeMainActivity()
								let mainSvr: any = main.getSystemService(context.LOCATION_SERVICE)
								let locationPermission: any = await permission.requestAndroidPermission(
									'android.permission.ACCESS_FINE_LOCATION'
								)
								if (locationPermission == 1) {
									console.log('已获得授权!')
								} else {
									uni.showModal({
										title: '温馨提示',
										content: '请开启位置信息权限',
										showCancel: true,
										success: res => {
											if (res.confirm) {
												permission.gotoAppPermissionSetting() // 打开权限设置界面
											} else {
												this.tip('需要开启位置信息才能继续操作')
											}
										}
									})
								}

								let result: any = permission.checkSystemEnableLocation()
								if (!result) {
									uni.showModal({
										title: '温馨提示',
										content: '请打开定位服务功能',
										showCancel: true,
										success: res => {
											if (res.confirm) {
												if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
													let Intent: any = plus.android.importClass('android.content.Intent')
													let Settings: any = plus.android.importClass('android.provider.Settings')
													let intent: any = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
													main.startActivity(intent) // 打开系统设置GPS服务页面
												} else {
													console.log('GPS功能已开启')
												}
											} else {
												this.tip('需要开启位置信息才能继续操作')
											}
										}
									})
								}
							}
						}
					})
					// #endif
					resolve(err)
				}
			})
		})
	},
	/**
	 * @name 下载文件
	 * @param {*} fileUrl
	 */
	downloadFile(fileUrl: string) {
		return new Promise(resolve => {
			uni.downloadFile({
				url: fileUrl,
				success: res => {
					if (res.statusCode === 200) {
						resolve(res.tempFilePath)
					}
				},
				fail: e => {
					console.log(`downloadFile error: ${e}`)
					this.tip('资源下载失败，请重试')
				}
			})
		})
	},
	/**
	 * @name html剔除富文本标签，留下纯文本
	 * @param html HTML字符串
	 */
	getSimpleText(html: string) {
		let re1 = new RegExp('<.+?>', 'g') // 匹配html标签的正则表达式，"g"是搜索匹配多个符合的内容
		let msg = html.replace(re1, '') // 执行替换成空字符
		return msg
	},
	/**
	 * @name 监听自定义返回
	 */
	customBack() {
		let pages = getCurrentPages()
		if (pages.length === 1) {
			uni.reLaunch({
				url: '/pages/index/index'
			})
		} else {
			uni.navigateBack()
		}
	},
	/**
	 * @name 七牛压缩以及域名处理
	 * @param {url} 七牛KEY或完整路径
	 * @param {width} 七牛图片压缩宽度高度自适应
	 * @param {type} 媒体类型默认图片可传video；image2则不转png
	 */
	qiniu(url: string, width = 750, type = 'image') {
		if (url && typeof url == 'string') {
			// 判断是否存在域名，然后返回媒体
			if (url.includes('http')) {
				if (type == 'image' && !url.includes('?')) {
					return `${url}?imageView2/2/w/${width}/format/png`
				}
				return url
			}
			if (type == 'image' && !url.includes('?')) {
				return `${$apis.imgBaseUrl}${url}?imageView2/2/w/${width}/format/png`
			}
			if (type == 'image2' && !url.includes('?')) {
				return `${$apis.imgBaseUrl}${url}?imageView2/2/w/${width}`
			}
			return `${$apis.imgBaseUrl}${url}`
		}
		return DefaultShareConfig.logo
	},
	/**
	 * @name 动态计算等比尺寸
	 * @param number 动态计算的值（750设计图）
	 */
	scale(number: number) {
		return (number / 750) * uni.getSystemInfoSync().windowWidth
	},
	/**
	 * @name 格式化W单位
	 * @param v 格式化单位的值
	 */
	formatNumber(v: number) {
		if (v > 9999) {
			return `${(v / 10000).toFixed(2)}w`
		}
		return v
	},
	/**
	 * 上传图片
	 * @param url
	 */
	uploadFilePromise(url: any) {
		return new Promise<{ hash: string; url: string }>(resolve => {
			$apis.qiniuToken(url, {
				success: (e: any) => {
					resolve({ url: this.qiniu(JSON.parse(e.data).hash), hash: JSON.parse(e.data).hash })
				}
			})
		})
	},
	/**
	 * 动态计算DOM信息
	 * @param {*} ele 元素ID/CLASS
	 * @param {*} _this 当前页面 this
	 * @returns
	 */
	createSelectorQuery(ele: any, _this: any) {
		return new Promise(resolve => {
			let selecQuery = uni.createSelectorQuery().in(_this)
			selecQuery.select(ele).boundingClientRect() // 获取首页顶部固定元素高度
			selecQuery.exec(res => {
				resolve(res[0])
			})
		})
	}
}

export default {
	...utils,
	...router
}
